from logging import getLogger
from urllib import quote
from copy import copy
from re import compile

from zope import schema
from zope.component import getMultiAdapter
from zope.formlib import form
from zope.interface import implements

from plone.app.portlets.portlets import base
from plone.memoize import ram, instance
from plone.memoize.compress import xhtml_compress
from plone.portlets.interfaces import IPortletDataProvider
from plone.app.portlets.cache import render_cachekey

from Acquisition import aq_inner
from Products.CMFCore.utils import getToolByName
from Products.CMFPlone import PloneMessageFactory as _

from meercat.ui.plone.browser.portlets.facetField import Renderer as FieldRenderer



log = getLogger('meercat.ui.plone.browser.portlets.facetMultiField')

_fq_re = compile(r'^(?P<field>\w+)(\((?P<label>[\w\s\d]+)\))?:(?P<value>.*)')

class IFacetMultiFieldPortlet(IPortletDataProvider):
    
    labels = schema.List(title=_(u'Titles'),
                         description=_(u'Displayed titles for the facet, one per '
                                       'line that will be matched with the field. '
                                       'There can be fewer titles than fields, '
                                       'once titles run out, the last one is '
                                       'used for the remaining fields'),
                         required=True,
                         min_length=1,
                         value_type=schema.TextLine())
    
    fields = schema.List(title=_(u'Fields'),
                         description=_(u'The fields (one per line) to facet on.'),
                         required=True,
                         min_length=2,
                         value_type=schema.TextLine())
    
    prefix = schema.TextLine(title=_(u'Prefix'),
                             description=_('Limit facet terms to those with this prefix'),
                             required=False)
    
    limit = schema.Int(title=_(u'Limit'),
                       description=_(u'The default maximum number of facet '
                                     'values to return'),
                       required=False)
    
    mincount = schema.Int(title=_(u'Minimum'),
                          description=_(u'The minimum count for a facet value '
                                        'for it to be displayed.'),
                          required=False)
    
    missing = schema.Bool(title=_(u'Include Missing'),
                          description=_(u'If selected, counts for fields with '
                                        'no value are included. i.e. if there '
                                        'is a facet on subject, it will list '
                                        'off the number of documents matching '
                                        'the query that have no subject'),
                          required=False)
    
    sort = schema.Bool(title=_(u'Sort by value'),
                       description=_(u'If true, terms will be sorted by value '
                                     'instead of by count'),
                       default=False)
    
    always = schema.Bool(title=_(u'Always Available'),
                         description=_(u'If enabled, this portlet will still be '
                                       'available after one of the facets has '
                                       'been selected.'),
                         default=True)
    
class Assignment(base.Assignment):
    implements(IFacetMultiFieldPortlet)
    
    def __init__(self, labels, fields, prefix=None, sort=True, limit=None,
                 mincount=None, missing=None, always=None):
        self.labels = labels
        self.fields = fields
        self.prefix = prefix
        self.sort = sort
        self.limit = limit
        self.mincount = mincount
        self.missing = missing
        self.always = always
    
    @property
    def title(self):
        return _(u"Facet Multi-Field: ") + ', '.join(self.labels)

class Renderer(FieldRenderer):
    def __init__(self, *args, **kwargs):
        super(Renderer, self).__init__(*args, **kwargs)
        
        fq = self.request.get('fq',[])
        if isinstance(fq,basestring):
            fq = [fq]
        
        fields = map(lambda f: f.groupdict()['field'],
                     filter(lambda f: f, map(_fq_re.match, fq)))
        
        labels = copy(self.data.labels)
        
        if len(labels) < len(self.data.fields):
            for i in range(len(labels),len(self.data.fields)):
                labels.append(self.data.labels[-1])
        
        index = 0
        
        for field in self.data.fields:
            if not field in fields:
                break
            
            index += 1
        
        self.label = labels[min((index,len(labels)-1,))]
        self.field = self.data.fields[min((index, len(self.data.fields)-1,))]

class AddForm(base.AddForm):
    form_fields = form.Fields(IFacetMultiFieldPortlet)
    label = _(u"Add Facet Multi-Field Portlet")
    description = _(u"This portlet lists facets for a multi-tiered field from a search.")
    
    def create(self, data):
        return Assignment(labels=data.get('labels'),
                          fields=data.get('fields'),
                          prefix=data.get('prefix',None),
                          sort=data.get('sort',None),
                          limit=data.get('limit',None),
                          mincount=data.get('mincount',None),
                          missing=data.get('missing',None),
                          always=data.get('always',None),)

class EditForm(base.EditForm):
    form_fields = form.Fields(IFacetMultiFieldPortlet)
    label = _(u"Edit Facet Multi-Field Portlet")
    description = AddForm.description
